home *** CD-ROM | disk | FTP | other *** search
/ Workbench Design / WB Collection.iso / workbench werkzeuge / uhren & terminkalender / time / pictureclock / pictureclock.c < prev    next >
C/C++ Source or Header  |  1996-04-07  |  26KB  |  939 lines

  1. #include <exec/types.h>
  2. #include <exec/memory.h>
  3. #include <exec/ports.h>
  4. #include <exec/io.h>
  5. #include <exec/devices.h>
  6. #include <dos/dos.h>
  7. #include <dos/dosextens.h>
  8. #include <dos/rdargs.h>
  9. #include <dos/dostags.h>
  10. #include <intuition/intuition.h>
  11. #include <intuition/screens.h>
  12. #include <intuition/icclass.h>
  13. #include <intuition/pointerclass.h>
  14. #include <graphics/view.h>
  15. #include <devices/timer.h>
  16. #include <devices/input.h>
  17. #include <devices/inputevent.h>
  18. #include <utility/date.h>
  19. #include <workbench/icon.h>
  20. #include <workbench/startup.h>
  21. #include <workbench/workbench.h>
  22. #include <datatypes/datatypesclass.h>
  23. #include <datatypes/pictureclass.h>
  24. #include <datatypes/soundclass.h>
  25.  
  26. #include <clib/alib_protos.h>
  27. #include <clib/exec_protos.h>
  28. #include <clib/dos_protos.h>
  29. #include <clib/intuition_protos.h>
  30. #include <clib/graphics_protos.h>
  31. #include <clib/utility_protos.h>
  32. #include <clib/timer_protos.h>
  33. #include <clib/wb_protos.h>
  34. #include <clib/icon_protos.h>
  35. #include <clib/datatypes_protos.h>
  36.  
  37. #include <stdlib.h>
  38. #include <stdarg.h>
  39. #include <string.h>
  40. #include <math.h>
  41.  
  42. #define NUMFILES    20
  43. #define MAXFILES    1000
  44. #define NAMESIZE    256
  45.  
  46. #define    SHIFT    0x60
  47. #define MAX_LONG    70000000L
  48. #define MILLION        100000L
  49.  
  50. #define    B_SHOW    0
  51. #define    B_RENDER    1
  52. #define    B_SWAP    2
  53. #define B_FREE    3
  54.  
  55. #define TITLE "PictureClock"
  56. #define OKAY "Okay"
  57. #define CANCEL "Cancel"
  58. #define OKCAN "Okay|Cancel"
  59.  
  60. #define NUM_OPTS    8
  61.  
  62. const UBYTE VERSION[]="$VER: PictureClock 39.72 (22-08-94)";
  63. UBYTE SoundProcName[]="PictureClock sound daemon";
  64. UBYTE TEMPLATE[]="PICTURE/A,SOUND,WAIT=WAITBETWEENSAMPLES/N,NOSEC/S,NOTICK/S,CONT=CONTINUOUS/S,BESTMODEID/S,SLIM/S";
  65. enum option_identifiers {PICTURE,SOUND,WAIT,NOSEC,NOTICK,CONT,BESTMODEID,SLIM};
  66. struct RDArgs *Arguments;
  67. struct DiskObject *ProgramIcon;
  68. ULONG options[NUM_OPTS];
  69.  
  70. extern __far struct Custom custom;
  71. extern struct DosLibrary *DOSBase;
  72. extern struct ExecBase *SysBase;
  73. extern struct WBStartup *_WBenchMsg;
  74.  
  75. struct Library *DataTypesBase;
  76. struct Library *TimerBase;
  77. struct Screen *MyScreen;
  78. struct Window *Front;
  79. struct BitMap *ExtraMap;
  80. struct Process *PictureClock,*Beieraar;
  81. struct ClockData CurrTime;
  82. struct timerequest TimerRequest;
  83. struct MsgPort *TimePort,*InputPort,*BufferPort[2];
  84. Object *Picture,*Sound;
  85. BPTR Handle;
  86. BOOL Workbench;
  87. __chip UWORD AreaData[25];
  88. struct AreaInfo ar_Info;
  89. struct TmpRas ar_Raster;
  90. PLANEPTR TempRaster;
  91.  
  92. struct DBufInfo *DoubleBuffer;
  93. struct BitMap *BufferMap[4];
  94. struct RastPort RenderPort;
  95.  
  96. struct InputEvent KeyPress;
  97. struct IOStdReq InputReq;
  98.  
  99. LONG Beierink,TimeCount;
  100. LONG X,Y,MX,MY,HX,HY;
  101. ULONG GreyPen,WhitePen,BlackPen,RedPen;
  102. LONG Left,Top,Right,Bottom,RadiusY,RadiusX,MiddleX,MiddleY,TopOffset;
  103. LONG tmpX1,tmpX2,tmpY1,tmpY2;
  104.  
  105. double angle,mangle,hangle,Sec,Min,Hour,HRX,HRY;
  106. double tmpRX,tmpRY;
  107. double HourFactor=0.4,MinFactor=1;
  108.  
  109.  
  110. struct TableCol {
  111.     ULONG Red,Green,Blue;
  112. };
  113.  
  114. struct LoadRGB32Table {
  115.     UWORD NumCols;
  116.     UWORD FirstCol;
  117.     struct TableCol Registers[256];
  118. } *Table;
  119.  
  120.  
  121. void CleanUp(void)
  122. {
  123.     LONG i;
  124.  
  125.     for(i=0; i<2; i++) if (BufferPort[i]) DeleteMsgPort(BufferPort[i]);
  126.     if (Arguments) FreeArgs(Arguments);
  127.     if (ProgramIcon) FreeDiskObject(ProgramIcon);
  128.     if (Front) CloseWindow(Front);
  129.     if (ExtraMap) FreeBitMap(ExtraMap);
  130.     if (BufferMap[B_FREE]) FreeBitMap(BufferMap[B_FREE]);
  131.  
  132.     if (Workbench) OpenWorkBench();
  133.     if (MyScreen) CloseScreen(MyScreen);
  134.  
  135.     if (DoubleBuffer) FreeDBufInfo(DoubleBuffer);
  136.     if (TempRaster) FreeRaster(TempRaster,MiddleX,MiddleY);
  137.     if (Picture) DisposeDTObject(Picture);
  138.     if (Table) FreeMem(Table,sizeof(struct LoadRGB32Table));
  139.  
  140.     if (TimerBase) CloseDevice((struct IORequest *) &TimerRequest);
  141.     if (TimePort) DeleteMsgPort(TimePort);
  142.     if (InputReq.io_Device) CloseDevice((struct IORequest *) &InputReq);
  143.     if (InputPort) DeleteMsgPort(InputPort);
  144.  
  145.     if (Beieraar) Signal((struct Task *) Beieraar,SIGBREAKF_CTRL_C);
  146.     if (Sound) DisposeDTObject(Sound);
  147.     if (DataTypesBase) CloseLibrary(DataTypesBase);
  148. }
  149.  
  150.  
  151. ULONG ExAllDoesntWorkAtAll(BPTR lock, struct FileInfoBlock *fib, UBYTE *Buffer[], ULONG BCount, ULONG AllocSize)
  152. {
  153.     struct DataType *dtn;
  154.     ULONG Buffer_t=0L;
  155.     BPTR FileLock;
  156.     UBYTE File[NAMESIZE],INFO[]="#?.info",Pattern[20];
  157.  
  158.     ParsePatternNoCase(INFO,Pattern,20);
  159.  
  160.     while (Buffer_t < BCount && ExNext(lock,fib)) {
  161.         if(fib->fib_DirEntryType > 0) continue;
  162.         if(MatchPatternNoCase(Pattern,fib->fib_FileName)) continue;
  163.  
  164.         NameFromLock(lock,File,NAMESIZE);
  165.         AddPart(File,fib->fib_FileName,NAMESIZE);
  166.  
  167.         if (FileLock=Lock(File,SHARED_LOCK)) {
  168.             if (dtn = ObtainDataTypeA (DTST_FILE, (APTR) FileLock, NULL)) {
  169.                 if (dtn->dtn_Header->dth_GroupID == GID_PICTURE) {
  170.                     Buffer[Buffer_t]=AllocMem(AllocSize,MEMF_CLEAR);
  171.                     if (Buffer[Buffer_t]) {
  172.                         strncpy(Buffer[Buffer_t],File,AllocSize);
  173.                         Buffer_t++;
  174.                     }
  175.                 }
  176.                 ReleaseDataType (dtn);
  177.             }
  178.             UnLock (FileLock);
  179.         }
  180.     }
  181.  
  182.     return(Buffer_t);
  183. }
  184.  
  185.         
  186. LONG Message(char *body, char *buttons,...)
  187. {
  188.     struct EasyStruct ER={sizeof(struct EasyStruct),0,0,NULL,NULL };
  189.     va_list arglist;
  190.  
  191.     ER.es_Title=TITLE" message";
  192.     ER.es_TextFormat=body;
  193.     ER.es_GadgetFormat=buttons;
  194.  
  195.     va_start(arglist,buttons);
  196.     return EasyRequestArgs(Front,&ER,0,(APTR) arglist);
  197.     va_end(arglist);
  198. }
  199.  
  200.  
  201. void __saveds BeierDeBeier(void)
  202. {
  203.     LONG sig;
  204.     struct dtTrigger Play;
  205.  
  206.     while (TRUE) {
  207.         sig=Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F);
  208.  
  209.         if (sig & SIGBREAKF_CTRL_C) return;
  210.         if (sig & SIGBREAKF_CTRL_F) {
  211.             if (TimeCount==0) {
  212.                 /* Make noise */
  213.                 Play.MethodID=DTM_TRIGGER;
  214.                 Play.dtt_GInfo=NULL;
  215.                 Play.dtt_Function=STM_PLAY;
  216.                 Play.dtt_Data=NULL;
  217.  
  218.                 DoDTMethodA(Sound,NULL,NULL,(Msg) &Play);
  219.                 Beierink--;
  220.                 if (options[WAIT] && Beierink) 
  221.                     TimeCount= * ((LONG *) options[WAIT]);
  222.             } else TimeCount--;
  223.         }
  224.     }
  225. }
  226.  
  227.  
  228. void DrawArms(void)
  229. {
  230.     ULONG Pen;
  231.  
  232.     /* Hour arm */
  233.     {
  234.         SetAPen(&RenderPort,GreyPen);
  235.  
  236.         tmpX1=(LONG) (sin(((Hour-HourFactor)/12) * 2 * PI) * tmpRX);
  237.         tmpY1=(LONG) (cos(((Hour-HourFactor)/12) * 2 * PI) * tmpRY);
  238.         tmpX2=(LONG) (sin(((Hour+HourFactor)/12) * 2 * PI) * tmpRX);
  239.         tmpY2=(LONG) (cos(((Hour+HourFactor)/12) * 2 * PI) * tmpRY);
  240.  
  241.         AreaMove(&RenderPort,MiddleX,MiddleY);
  242.         AreaDraw(&RenderPort,MiddleX+tmpX1,MiddleY-tmpY1);
  243.         AreaDraw(&RenderPort,MiddleX+HX,MiddleY-HY);
  244.         AreaDraw(&RenderPort,MiddleX+tmpX2,MiddleY-tmpY2);
  245.         AreaEnd(&RenderPort);
  246.  
  247.         if (tmpY1 > tmpY2) Pen=WhitePen; else Pen=BlackPen;
  248.         if (tmpY1 == tmpY2) {
  249.             if (tmpX1 < tmpX2) Pen=WhitePen; else Pen=BlackPen;
  250.         }
  251.         SetAPen(&RenderPort,Pen);
  252.         Move(&RenderPort,MiddleX,MiddleY);
  253.         Draw(&RenderPort,MiddleX+tmpX1,MiddleY-tmpY1);
  254.         Draw(&RenderPort,MiddleX+HX,MiddleY-HY);
  255.  
  256.         if (Pen == BlackPen) Pen=WhitePen; else Pen=BlackPen;
  257.         SetAPen(&RenderPort,Pen);
  258.         Draw(&RenderPort,MiddleX+tmpX2,MiddleY-tmpY2);
  259.         Draw(&RenderPort,MiddleX,MiddleY);
  260.     }
  261.  
  262.     /* Minute arm */
  263.     {
  264.         SetAPen(&RenderPort,GreyPen);
  265.  
  266.         tmpX1=(LONG) (sin(((Min-MinFactor)/60) * 2 * PI) * HRX);
  267.         tmpY1=(LONG) (cos(((Min-MinFactor)/60) * 2 * PI) * HRY);
  268.         tmpX2=(LONG) (sin(((Min+MinFactor)/60) * 2 * PI) * HRX);
  269.         tmpY2=(LONG) (cos(((Min+MinFactor)/60) * 2 * PI) * HRY);
  270.  
  271.         AreaMove(&RenderPort,MiddleX,MiddleY);
  272.         AreaDraw(&RenderPort,MiddleX+tmpX1,MiddleY-tmpY1);
  273.         AreaDraw(&RenderPort,MiddleX+MX,MiddleY-MY);
  274.         AreaDraw(&RenderPort,MiddleX+tmpX2,MiddleY-tmpY2);
  275.         AreaEnd(&RenderPort);
  276.  
  277.         if (tmpY1 > tmpY2) Pen=WhitePen; else Pen=BlackPen;
  278.         if (tmpY1 == tmpY2) {
  279.             if (tmpX1 < tmpX2) Pen=WhitePen; else Pen=BlackPen;
  280.         }
  281.         SetAPen(&RenderPort,Pen);
  282.         Move(&RenderPort,MiddleX,MiddleY);
  283.         Draw(&RenderPort,MiddleX+tmpX1,MiddleY-tmpY1);
  284.         Draw(&RenderPort,MiddleX+MX,MiddleY-MY);
  285.  
  286.         if (Pen == BlackPen) Pen=WhitePen; else Pen=BlackPen;
  287.         SetAPen(&RenderPort,Pen);
  288.         Draw(&RenderPort,MiddleX+tmpX2,MiddleY-tmpY2);
  289.         Draw(&RenderPort,MiddleX,MiddleY);
  290.     }
  291. }
  292.  
  293. int main(void)
  294. {
  295.     LONG ModeID,ID,i,WinMask,TimeMask,sig,Cols,Address,WBWait;
  296.     LONG PixelX,PixelY,ExtraY=0;        /* For aspect ratio's sake */
  297.     LONG DirFiles=0;
  298.     BOOL RUNNING=TRUE,EXIT=FALSE;
  299.     Object *MousePointer;
  300.     UBYTE **tools,*s,**File,*ex_File[NUMFILES];
  301.     struct WBArg *Args=_WBenchMsg->sm_ArgList;
  302.     struct ColorRegister *Colours;
  303.     struct ColorMap *CMap;
  304.     struct BitMapHeader *BMHD;
  305.     struct IntuiMessage *imsg;
  306.     struct Rectangle ScreenDimensions;
  307.  
  308.     struct TableCol Grey = {(170 << 24), (170 << 24), (170 << 24)};
  309.     struct TableCol White = {0xffffffff, 0xffffffff, 0xffffffff};
  310.     struct TableCol Black = {0L,0L,0L};
  311.     struct TableCol Red = {0xffffffff, 0L, 0L};
  312.  
  313.     struct FileInfoBlock *fib;
  314.     UBYTE FileName[NAMESIZE];
  315.  
  316.     struct TagItem *tstate, *tag;
  317.     struct TagItem *tags;
  318.     ULONG tidata,RandNumber,ex_Ret;
  319.  
  320.     i=DOSBase->dl_lib.lib_Version;
  321.     if (i < 39) {
  322.         if (i >= 36) Message("This program requires Kickstart V39\nor higher to run.",CANCEL);
  323.         exit(40);
  324.     }
  325.  
  326.     PictureClock=(struct Process *) FindTask(NULL);
  327.     if (PictureClock->pr_CLI) {
  328.         Arguments=ReadArgs(TEMPLATE,options,NULL);
  329.         if (! Arguments) {
  330.             Printf("Usage: PictureClock %s\n",TEMPLATE);
  331.             exit(10);
  332.         }
  333.     } else {    // if WB
  334.         if (ProgramIcon=GetDiskObject(Args->wa_Name)) {
  335.             tools=(UBYTE **) ProgramIcon->do_ToolTypes;
  336.  
  337.             if (_WBenchMsg->sm_NumArgs == 1) {
  338.                 s=(UBYTE *) FindToolType(tools,"PICTURE");
  339.                 if (s) options[PICTURE]=(ULONG) s; else {
  340.                     Message("You have to specify a\npicture file or dir !",CANCEL);
  341.                     exit(10);
  342.                 }
  343.             } else { 
  344.                 NameFromLock(Args[_WBenchMsg->sm_NumArgs-1].wa_Lock,FileName,NAMESIZE);
  345.                 AddPart(FileName,Args[_WBenchMsg->sm_NumArgs-1].wa_Name,NAMESIZE);
  346.                 options[PICTURE]=(ULONG) FileName;
  347.             }
  348.  
  349.             s=(UBYTE *) FindToolType(tools,"SOUND");
  350.             if (s) options[SOUND]=(ULONG) s;
  351.  
  352.             s=(UBYTE *) FindToolType(tools,"WAITBETWEENSAMPLES");
  353.             if (s) {
  354.                 WBWait=atol(s);
  355.                 options[WAIT]=(ULONG) &WBWait;
  356.             } else if (s=(UBYTE *) FindToolType(tools,"WAIT")) {
  357.                 WBWait=atol(s);
  358.                 options[WAIT]=(ULONG) &WBWait;
  359.             }
  360.  
  361.             s=(UBYTE *) FindToolType(tools,"NOSEC");
  362.             if (s) options[NOSEC]=TRUE;
  363.  
  364.             s=(UBYTE *) FindToolType(tools,"NOTICK");
  365.             if (s) options[NOTICK]=TRUE;
  366.  
  367.             s=(UBYTE *) FindToolType(tools,"CONT");
  368.             if (s) options[CONT]=TRUE;
  369.  
  370.             s=(UBYTE *) FindToolType(tools,"CONTINUOUS");
  371.             if (s) options[CONT]=TRUE;
  372.  
  373.             s=(UBYTE *) FindToolType(tools,"BESTMODEID");
  374.             if (s) options[BESTMODEID]=TRUE;
  375.  
  376.             s=(UBYTE *) FindToolType(tools,"SLIM");
  377.             if (s) options[SLIM]=TRUE;
  378.         }
  379.     }
  380.     strncpy(FileName,(UBYTE *) options[PICTURE],NAMESIZE);
  381.  
  382.     DataTypesBase=OpenLibrary("datatypes.library",39L);
  383.     if (! DataTypesBase) {
  384.         Message("Can't open datatypes.library V39 !",CANCEL);
  385.         exit(10);
  386.     }
  387.  
  388.     if (options[SLIM]) {
  389.         HourFactor=.25;
  390.         MinFactor=.6;
  391.     }
  392.  
  393.     if (options[SOUND]) {
  394.         Sound=NewDTObject((APTR) options[SOUND],
  395.             DTA_GroupID, GID_SOUND,
  396.             SDTA_Volume, 64,
  397.             SDTA_Cycles, 1,
  398.             TAG_DONE);
  399.         if (Sound) {
  400.             Beieraar=CreateNewProcTags(    NP_Entry, BeierDeBeier,
  401.                 NP_StackSize, 1024,
  402.                 NP_Priority, -2,
  403.                 NP_Output, Open("CON:11/11/320/80/Beieraar/AUTO/WAIT",MODE_NEWFILE),
  404.                 NP_Name, SoundProcName,
  405.                 TAG_DONE);
  406.         } else {
  407.             if (! Message("Can't open %s as a sound sample file !\nDo you wish to continue anyway ?",OKCAN,options[SOUND]))
  408.                 exit(0);
  409.         }
  410.     }
  411.         
  412.     if (! (Handle=Lock(FileName,SHARED_LOCK))) {
  413.         Message("Can't find %s !",CANCEL,FileName);
  414.         exit(20);
  415.     }
  416.  
  417.     fib=AllocDosObject(DOS_FIB,NULL);
  418.     if (! fib) {
  419.         Message("Can't allocate FileInfoBlock !",CANCEL);
  420.         UnLock(Handle);
  421.         exit(20);
  422.     } else {
  423.         Examine(Handle,fib);
  424.         if (fib->fib_DirEntryType > 0) {    // is a dir
  425.             File=AllocMem(MAXFILES*sizeof(UBYTE *),MEMF_CLEAR);
  426.             if (! File) {
  427.                 Message("Out of memory !",CANCEL);
  428.                 UnLock(Handle);
  429.                 FreeDosObject(DOS_FIB,(void *) fib);
  430.                 exit(20);
  431.             }
  432.  
  433.             while(ex_Ret=ExAllDoesntWorkAtAll(Handle,fib,ex_File,NUMFILES,NAMESIZE)) {
  434.                 for(i=0; i<ex_Ret; i++) {
  435.                     if (DirFiles < MAXFILES) {
  436.                         File[DirFiles]=AllocMem(NAMESIZE,MEMF_CLEAR);
  437.                         if (File[DirFiles]) {
  438.                             strncpy(File[DirFiles],ex_File[i],NAMESIZE);
  439.                             FreeMem(ex_File[i],NAMESIZE);
  440.                             DirFiles++;
  441.                         }
  442.                     }
  443.                 }
  444.             }
  445.  
  446.             if (IoErr() != ERROR_NO_MORE_ENTRIES) {
  447.                 Message("ExAllDoesntWorkAtAll() failed with\nDOS error code #%ld",CANCEL,IoErr());
  448.  
  449.                 for(i=0; i<DirFiles; i++) 
  450.                     if (File[i]) FreeMem(File[i],NAMESIZE);
  451.                 FreeMem(File,MAXFILES*sizeof(UBYTE *));
  452.  
  453.                 exit(20);
  454.             }
  455.  
  456.             if (DirFiles == 0) {
  457.                 Message("Directory\n%s\ncontains no picture files.",CANCEL,FileName);
  458.                 FreeMem(File,MAXFILES*sizeof(UBYTE *));
  459.                 exit(10);
  460.             }
  461.  
  462.             /* Get a random number the Murty Termoes way :-) */
  463.             do {
  464.                 srand(custom.vhposr);
  465.                 { rand(); rand(); rand(); }
  466.                 RandNumber=(rand() * DirFiles)/MAX_LONG;
  467.             } while (RandNumber >= DirFiles);
  468.             strncpy(FileName,File[RandNumber],NAMESIZE);
  469.  
  470.             for(i=0; i<DirFiles; i++) 
  471.                 if (File[i]) FreeMem(File[i],NAMESIZE);
  472.             FreeMem(File,MAXFILES*sizeof(UBYTE *));
  473.         }
  474.     }
  475.     FreeDosObject(DOS_FIB,(void *) fib);
  476.  
  477.     atexit(CleanUp);
  478.  
  479.     Table=(struct LoadRGB32Table *) AllocMem(sizeof(struct LoadRGB32Table),MEMF_CLEAR);
  480.     if (! Table) exit(20);
  481.  
  482.     TimePort=CreateMsgPort();
  483.     if (! TimePort) {
  484.         Message("Can't open MsgPort for timer.device !",CANCEL);
  485.         exit(20);
  486.     } else TimeMask=(1L << TimePort->mp_SigBit);
  487.  
  488.     TimerRequest.tr_node.io_Message.mn_ReplyPort=TimePort;
  489.     TimerRequest.tr_node.io_Command=TR_ADDREQUEST;
  490.     TimerRequest.tr_time.tv_secs=1L;
  491.  
  492.     if (OpenDevice(TIMERNAME,UNIT_WAITUNTIL,(struct IORequest *) &TimerRequest,0L)) {
  493.         Message("Can't open timer.device !",CANCEL);
  494.         exit(25);
  495.     } else {
  496.         TimerBase=(struct Library *) TimerRequest.tr_node.io_Device;
  497.         /* Send the request now, when the picture is there, we can draw
  498.            the clock straight away.                                     */
  499.         SendIO((struct IORequest *) &TimerRequest);
  500.     }
  501.  
  502.     InputPort=CreateMsgPort();
  503.     if (! InputPort) {
  504.         Message("Can't open MsgPort for input.device !",CANCEL);
  505.         exit(20);
  506.     }
  507.     InputReq.io_Message.mn_ReplyPort=InputPort;
  508.     InputReq.io_Command=IND_WRITEEVENT;
  509.     InputReq.io_Flags=IOF_QUICK;
  510.     InputReq.io_Length=sizeof(struct InputEvent);
  511.     InputReq.io_Data=&KeyPress;
  512.  
  513.     if (OpenDevice("input.device",0,(struct IORequest *) &InputReq,0)) {
  514.         Message("Can't open input.device !",CANCEL);
  515.         exit(20);
  516.     }
  517.  
  518.     Picture=NewDTObject((APTR) FileName,
  519.         DTA_GroupID, GID_PICTURE,
  520.         PDTA_Remap, FALSE,
  521.         TAG_DONE);
  522.     UnLock(Handle);
  523.     if (! Picture) {
  524.         Message("datatypes.library error #%ld",CANCEL,IoErr());
  525.         exit(20);
  526.     }
  527.  
  528.     GetDTAttrs(Picture,    PDTA_ModeID, &ModeID,
  529.                         PDTA_BitMapHeader, &BMHD,
  530.                         PDTA_ColorRegisters, &Address,
  531.                         PDTA_NumColors, &Cols,
  532.                         TAG_DONE);
  533.     if (options[BESTMODEID]) {
  534.         ID=BestModeID(    BIDTAG_DIPFMustNotHave, DIPF_IS_HAM,
  535.                         BIDTAG_DesiredWidth, BMHD->bmh_Width,
  536.                         BIDTAG_DesiredHeight, BMHD->bmh_Height,
  537.                         BIDTAG_Depth, BMHD->bmh_Depth,
  538.                         TAG_DONE);
  539.         if (ID == INVALID_ID) {
  540.             if (! Message("BestModeID() couldn't come up with anything.\nUse the picture's default ModeID ?",OKCAN)) exit(0);
  541.         } else {
  542.             ModeID=ID;
  543.         }
  544.     }
  545.  
  546.     {
  547.         if (ModeID & HAM) {
  548.             Message("Sorry, HAM pictures are not supported.",OKAY);
  549.             exit(0);
  550.         }
  551.  
  552.         Table->NumCols=Cols;
  553.  
  554.         for(i=0; i<Cols; i++) {
  555.             Colours=(struct ColorRegister *) (Address + i * sizeof(struct ColorRegister));
  556.  
  557.             Table->Registers[i].Red=Colours->red << 24;
  558.             Table->Registers[i].Green=Colours->green << 24;
  559.             Table->Registers[i].Blue=Colours->blue << 24;
  560.         }
  561.     }
  562.  
  563.     Workbench=CloseWorkBench();
  564.  
  565.     /* Get standard overscan dimensions */
  566.     QueryOverscan(ModeID,&ScreenDimensions,OSCAN_STANDARD);
  567.     PixelX=X=ScreenDimensions.MaxX - ScreenDimensions.MinX + 1;
  568.     PixelY=Y=ScreenDimensions.MaxY - ScreenDimensions.MinY + 1;
  569.     if (X > BMHD->bmh_Width) {
  570.         ScreenDimensions.MinX=(X-BMHD->bmh_Width)/2;
  571.         ScreenDimensions.MaxX=ScreenDimensions.MinX + BMHD->bmh_Width;
  572.     }
  573.     if (Y > BMHD->bmh_Height) {
  574.         TopOffset=(Y-BMHD->bmh_Height)/2;
  575.         ScreenDimensions.MaxY=BMHD->bmh_Height + TopOffset;
  576.     } else TopOffset=0;
  577.  
  578.     /* Now calculate the new screen dimemsions and open the screen */
  579.     X=ScreenDimensions.MaxX - ScreenDimensions.MinX + 1;
  580.     Y=ScreenDimensions.MaxY - ScreenDimensions.MinY + 1;
  581.     MyScreen=OpenScreenTags(NULL,    SA_Left, ScreenDimensions.MinX,
  582.                                     SA_Top, ScreenDimensions.MinY,
  583.                                     SA_Width, X,
  584.                                     SA_Height, Y,
  585.                                     SA_Depth, BMHD->bmh_Depth,
  586.                                     SA_Type, CUSTOMSCREEN,
  587.                                     SA_DisplayID, ModeID,
  588.                                     SA_ShowTitle, FALSE,
  589.                                     SA_DClip, &ScreenDimensions, 
  590.                                     SA_Colors32, Table,
  591.                                     TAG_DONE); 
  592.     if (! MyScreen) {
  593.         Message("OpenScreen() failed",CANCEL);
  594.         exit(20);
  595.     } else CMap=MyScreen->ViewPort.ColorMap;
  596.  
  597.     DoubleBuffer=AllocDBufInfo(&MyScreen->ViewPort);
  598.     if (! DoubleBuffer) {
  599.         Message("Can't allocate DoubleBuffer info !",CANCEL);
  600.         exit(20);
  601.     } else {
  602.         BufferPort[0]=CreateMsgPort();
  603.         BufferPort[1]=CreateMsgPort();
  604.         if (! (BufferPort[0] && BufferPort[1])) {
  605.             Message("Can't allocate MsgPort(s) !",CANCEL);
  606.             exit(20);
  607.         }
  608.  
  609.         DoubleBuffer->dbi_SafeMessage.mn_ReplyPort=BufferPort[0];
  610.         DoubleBuffer->dbi_DispMessage.mn_ReplyPort=BufferPort[1];
  611.     }
  612.  
  613.     Front=OpenWindowTags(NULL,    WA_Left, 0,
  614.                                 WA_Top, 0,
  615.                                 WA_Width, MyScreen->Width,
  616.                                 WA_Height, MyScreen->Height,
  617.                                 WA_IDCMP, IDCMP_IDCMPUPDATE|IDCMP_MOUSEBUTTONS,
  618.                                 WA_CustomScreen, MyScreen,
  619.                                 WA_SimpleRefresh, TRUE,
  620.                                 WA_Borderless, TRUE,
  621.                                 WA_BusyPointer, TRUE,
  622.                                 WA_RMBTrap, TRUE,
  623.                                 WA_Activate, TRUE,
  624.                                 TAG_DONE);
  625.     if (! Front) {
  626.         Message("Can't open window !",CANCEL);
  627.         exit(20);
  628.     } else {
  629.         WinMask=1L << Front->UserPort->mp_SigBit;
  630.         BufferMap[B_SHOW]=Front->RPort->BitMap;
  631.  
  632.         MiddleX=Front->Width/2;
  633.         MiddleY=(Front->Height + TopOffset)/2;
  634.     }
  635.  
  636.     BufferMap[B_RENDER]=AllocBitMap(MyScreen->Width,MyScreen->Height,BMHD->bmh_Depth,BMF_CLEAR|BMF_DISPLAYABLE,NULL);
  637.     if (! BufferMap[B_RENDER]) {
  638.         Message("Can't allocate DoubleBuffer BitMap !",CANCEL);
  639.         exit(20);
  640.     } else {
  641.         BufferMap[B_FREE]=BufferMap[B_RENDER];
  642.  
  643.         TempRaster=AllocRaster(MiddleX,MiddleY);
  644.         if (! TempRaster) {
  645.             Message("Can't allocate raster memory !",CANCEL);
  646.             exit(20);
  647.         }
  648.         InitArea(&ar_Info,AreaData,10);
  649.         InitTmpRas(&ar_Raster,TempRaster,RASSIZE(MiddleX,MiddleY));    
  650.         InitRastPort(&RenderPort);
  651.         RenderPort.BitMap=BufferMap[B_RENDER];
  652.         RenderPort.AreaInfo=&ar_Info;
  653.         RenderPort.TmpRas=&ar_Raster;
  654.     }
  655.  
  656.     ExtraMap=AllocBitMap(Front->Width,Front->Height,BMHD->bmh_Depth,0,NULL);
  657.     if (! ExtraMap) {
  658.         Message("Can't allocate extra BitMap !",CANCEL);
  659.         exit(20);
  660.     }
  661.  
  662.     SetDTAttrs(Picture,NULL,NULL,    GA_Left, 0,
  663.                                     GA_Top, TopOffset,    
  664.                                     GA_Width, Front->Width,
  665.                                     GA_Height, Front->Height - TopOffset,
  666.                                     ICA_TARGET, ICTARGET_IDCMP,
  667.                                     TAG_DONE);
  668.     AddDTObject(Front,NULL,Picture,-1L);
  669.     RefreshDTObjects(Picture,Front,NULL,NULL);
  670.  
  671.     while(RUNNING) {
  672.         sig=Wait(WinMask | SIGBREAKF_CTRL_C);
  673.  
  674.         if (sig & SIGBREAKF_CTRL_C) { RUNNING=FALSE; EXIT=TRUE; }
  675.  
  676.         while (imsg = (struct IntuiMessage *) GetMsg (Front->UserPort)) {
  677.             switch (imsg->Class)
  678.             {
  679.                 case IDCMP_IDCMPUPDATE:
  680.                 tstate = tags = (struct TagItem *) imsg->IAddress;
  681.                 while (tag = NextTagItem (&tstate))
  682.                 {
  683.                     tidata = tag->ti_Data;
  684.                     switch (tag->ti_Tag)
  685.                     {
  686.                     case DTA_Busy:
  687.                         if (tidata)
  688.                         SetWindowPointer (Front, WA_BusyPointer, TRUE, TAG_DONE);
  689.                         else
  690.                         SetWindowPointer (Front, WA_Pointer, NULL, TAG_DONE);
  691.                         break;
  692.  
  693.                     case DTA_Sync:
  694.                         RefreshDTObjects (Picture, Front, NULL, NULL);
  695.                         RUNNING=FALSE;
  696.                         break;
  697.                     }
  698.                 }
  699.                 break;
  700.             }
  701.  
  702.             /* Done with the message, so reply to it */
  703.             ReplyMsg ((struct Message *) imsg);
  704.         }
  705.     }
  706.  
  707.     RemoveDTObject(Front,Picture);
  708.     DisposeDTObject(Picture);
  709.     Picture=NULL;
  710.  
  711.     if (EXIT) exit(0);
  712.  
  713.     MousePointer=NewObject(NULL,POINTERCLASS,
  714.         POINTERA_BitMap, BufferMap[B_FREE],
  715.         POINTERA_WordWidth, 1L,
  716.         TAG_DONE);
  717.     if (MousePointer) SetWindowPointer(Front,WA_Pointer,MousePointer,TAG_DONE);
  718.  
  719.     GreyPen=FindColor(CMap,Grey.Red,Grey.Green,Grey.Blue,Cols);
  720.     WhitePen=FindColor(CMap,White.Red,White.Green,White.Blue,Cols);
  721.     BlackPen=FindColor(CMap,Black.Red,Black.Green,Black.Blue,Cols);
  722.     RedPen=FindColor(CMap,Red.Red,Red.Green,Red.Blue,Cols);
  723.  
  724.     SetAPen(Front->RPort,GreyPen);
  725.     SetDrMd(Front->RPort,JAM1);
  726.  
  727.     if ((Front->Height - TopOffset) > Front->Width)
  728.         ExtraY=(Front->Height - TopOffset - Front->Width)/2;
  729.  
  730.     /* 12 o' clock */
  731.     {
  732.         tmpX1=(40 * PixelX)/700;
  733.         tmpX2=tmpX1/2;
  734.  
  735.         Left=(Front->Width-tmpX1-5)/2;
  736.         Right=Front->Width-Left;
  737.  
  738.         Top=TopOffset + ExtraY + ((5 * PixelX)/300);
  739.         Bottom=Front->Height - ExtraY - ((5 * PixelX)/300);
  740.         RadiusY=(Bottom-Top)/2;
  741.         RadiusX=RadiusY * (PixelX/PixelY);
  742.         Bottom=Top + (RadiusY / 3);
  743.  
  744.         RectFill(Front->RPort,Left,Top,Right-tmpX2-5,Bottom);
  745.         RectFill(Front->RPort,Left+tmpX2+5,Top,Right,Bottom);
  746.  
  747.         SetAPen(Front->RPort,WhitePen);
  748.         Move(Front->RPort,Left,Bottom);
  749.         Draw(Front->RPort,Left,Top);
  750.         Draw(Front->RPort,Left+tmpX2,Top);
  751.  
  752.         SetAPen(Front->RPort,BlackPen);
  753.         Draw(Front->RPort,Left+tmpX2,Bottom);
  754.         Draw(Front->RPort,Left+1,Bottom);
  755.  
  756.         SetAPen(Front->RPort,WhitePen);
  757.         Move(Front->RPort,Left+tmpX2+5,Bottom);
  758.         Draw(Front->RPort,Left+tmpX2+5,Top);
  759.         Draw(Front->RPort,Left+tmpX1+5,Top);
  760.  
  761.         SetAPen(Front->RPort,BlackPen);
  762.         Draw(Front->RPort,Left+tmpX1+5,Bottom);
  763.         Draw(Front->RPort,Left+tmpX2+5+1,Bottom);
  764.     }
  765.  
  766.     /* 6 o' clock */
  767.     {
  768.         Left=(Front->Width-tmpX2)/2;
  769.         Right=Front->Width-Left;
  770.  
  771.         Bottom=Front->Height - ExtraY - ((5 * PixelX)/300);
  772.         Top=Bottom-(RadiusY / 3);
  773.  
  774.         SetAPen(Front->RPort,GreyPen);
  775.         RectFill(Front->RPort,Left,Top,Right,Bottom);
  776.  
  777.         SetAPen(Front->RPort,WhitePen);
  778.         Move(Front->RPort,Left,Bottom);
  779.         Draw(Front->RPort,Left,Top);
  780.         Draw(Front->RPort,Right,Top);
  781.  
  782.         SetAPen(Front->RPort,BlackPen);
  783.         Draw(Front->RPort,Right,Bottom);
  784.         Draw(Front->RPort,Left+1,Bottom);
  785.     }
  786.  
  787.     /* 3 o' clock */
  788.     {
  789.         Top=MiddleY - ((8 * PixelY)/500);
  790.         Bottom=Top +  ((16 * PixelY)/500);
  791.         Right=MiddleX + RadiusX;
  792.         Left=Right - (RadiusX/3);
  793.  
  794.         SetAPen(Front->RPort,GreyPen);
  795.         RectFill(Front->RPort,Left,Top,Right,Bottom);
  796.  
  797.         SetAPen(Front->RPort,WhitePen);
  798.         Move(Front->RPort,Left,Bottom);
  799.         Draw(Front->RPort,Left,Top);
  800.         Draw(Front->RPort,Right,Top);
  801.  
  802.         SetAPen(Front->RPort,BlackPen);
  803.         Draw(Front->RPort,Right,Bottom);
  804.         Draw(Front->RPort,Left+1,Bottom);
  805.     }
  806.  
  807.     /* 9 o' clock */
  808.     {
  809.         Left=MiddleX - RadiusX;
  810.         Right=Left + (RadiusX/3);
  811.  
  812.         SetAPen(Front->RPort,GreyPen);
  813.         RectFill(Front->RPort,Left,Top,Right,Bottom);
  814.  
  815.         SetAPen(Front->RPort,WhitePen);
  816.         Move(Front->RPort,Left,Bottom);
  817.         Draw(Front->RPort,Left,Top);
  818.         Draw(Front->RPort,Right,Top);
  819.  
  820.         SetAPen(Front->RPort,BlackPen);
  821.         Draw(Front->RPort,Right,Bottom);
  822.         Draw(Front->RPort,Left+1,Bottom);
  823.     }
  824.  
  825.     BltBitMap(Front->RPort->BitMap,0,0,ExtraMap,0,0,Front->Width,Front->Height,0x0C0,0xff,NULL);
  826.     BltBitMap(Front->RPort->BitMap,0,0,BufferMap[B_RENDER],0,0,Front->Width,Front->Height,0x0C0,0xff,NULL);
  827.     WaitBlit();
  828.  
  829.     RUNNING=TRUE;
  830.     HRX=(RadiusX * 2)/3;
  831.     HRY=(RadiusY * 2)/3;
  832.     tmpRX=RadiusX / 2;
  833.     tmpRY=RadiusY / 2;
  834.  
  835.     while(RUNNING) {
  836.         sig=Wait(TimeMask | WinMask | SIGBREAKF_CTRL_C);
  837.  
  838.         if (sig & SIGBREAKF_CTRL_C) RUNNING=FALSE;
  839.  
  840.         if (sig & WinMask && RUNNING) {
  841.             while (imsg = (struct IntuiMessage *) GetMsg (Front->UserPort)) {
  842.                 switch (imsg->Class)
  843.                 {
  844.                     case IDCMP_MOUSEBUTTONS :    RUNNING=FALSE;
  845.                                                 break;
  846.                 }
  847.  
  848.                 /* Done with the message, so reply to it */
  849.                 ReplyMsg ((struct Message *) imsg);
  850.             }
  851.         }
  852.  
  853.         if (sig & TimeMask && RUNNING) {
  854.             GetSysTime(&TimerRequest.tr_time);
  855.             Amiga2Date(TimerRequest.tr_time.tv_secs,&CurrTime);
  856.             TimerRequest.tr_time.tv_secs+=1L;
  857.             SendIO((struct IORequest *) &TimerRequest);
  858.  
  859.             /* Calculate all the new values */
  860.             {
  861.                 Sec=CurrTime.sec;
  862.                 Min=CurrTime.min;
  863.                 Hour=(CurrTime.hour > 12) ? CurrTime.hour-12 : CurrTime.hour;
  864.  
  865.                 if (Sec==0) {
  866.                     TimeCount=0;
  867.                     if (Min==30) Beierink=1;
  868.                     if (Min==0) Beierink=Hour;
  869.                 }
  870.  
  871.                 if (options[CONT]) Min+=(Sec/60);
  872.                 Hour+=(Min/60);
  873.  
  874.                 angle=(Sec/60) * 2 * PI;    /* Angle in radials */
  875.                 mangle=(Min/60) * 2 * PI;
  876.                 hangle=(Hour/12) * 2 * PI;
  877.  
  878.                 X=(LONG) (sin(angle) * RadiusX);
  879.                 Y=(LONG) (cos(angle) * RadiusY);
  880.                 MX=(LONG) (sin(mangle) * RadiusX);
  881.                 MY=(LONG) (cos(mangle) * RadiusY);
  882.                 HX=(LONG) (sin(hangle) * HRX);
  883.                 HY=(LONG) (cos(hangle) * HRY);
  884.             }
  885.  
  886.             if (! options[NOTICK]) {
  887.                 /* Simulate a keypress, the left shift in this case.
  888.                    Together with Yak, this makes a nice, ticking sound.  */
  889.                 memset(&KeyPress,0,sizeof(struct InputEvent));
  890.                 KeyPress.ie_Class=IECLASS_RAWKEY;
  891.                 KeyPress.ie_Code=SHIFT;
  892.                 DoIO((struct IORequest *) &InputReq);
  893.  
  894.                 /* And up again */
  895.                 memset(&KeyPress,0,sizeof(struct InputEvent));
  896.                 KeyPress.ie_Class=IECLASS_RAWKEY;
  897.                 KeyPress.ie_Code=SHIFT | IECODE_UP_PREFIX;
  898.                 DoIO((struct IORequest *) &InputReq);
  899.             }
  900.  
  901.             if (Beieraar && Beierink) {
  902.                 Signal((struct Task *) Beieraar,SIGBREAKF_CTRL_F);
  903.             }
  904.  
  905.             DrawArms();        /* Draw minute and hour hands */
  906.  
  907.             if (! options[NOSEC]) {
  908.                 SetAPen(&RenderPort,RedPen);
  909.                 Move(&RenderPort,MiddleX,MiddleY);
  910.                 Draw(&RenderPort,MiddleX+X,MiddleY-Y);
  911.             }
  912.  
  913.             ChangeVPBitMap(&MyScreen->ViewPort,BufferMap[B_RENDER],DoubleBuffer);
  914.  
  915.             /* Wait until it is safe to write to the BitMap */
  916.             while(! GetMsg(DoubleBuffer->dbi_SafeMessage.mn_ReplyPort)) 
  917.                 Wait(1L << (DoubleBuffer->dbi_SafeMessage.mn_ReplyPort->mp_SigBit));
  918.  
  919.             BufferMap[B_SWAP]=BufferMap[B_SHOW];
  920.             BufferMap[B_SHOW]=BufferMap[B_RENDER];
  921.             BufferMap[B_RENDER]=BufferMap[B_SWAP];
  922.             RenderPort.BitMap=BufferMap[B_RENDER];
  923.  
  924.             BltBitMap(ExtraMap,0,0,BufferMap[B_RENDER],0,0,Front->Width,Front->Height,0x0C0,0xff,NULL);
  925.  
  926.             /* Wait until it is safe to swap the BitMaps, then you won't
  927.                have to do it next time around.                           */
  928.             while(! GetMsg(DoubleBuffer->dbi_DispMessage.mn_ReplyPort)) 
  929.                 Wait(1L << (DoubleBuffer->dbi_DispMessage.mn_ReplyPort->mp_SigBit));
  930.         }
  931.     }
  932.  
  933.     if (MousePointer) {
  934.         DisposeObject(MousePointer);
  935.         SetWindowPointer(Front,WA_Pointer,NULL,TAG_DONE);
  936.     }
  937.     exit(0);
  938. }
  939.